﻿#include "contactitem.h"
#include <librtc.h>
#include "clientcallback.h"
#include "globaltools.h"
#include "Hanz2Piny.h"
#include "litedb.h"

static const int width = 40;
static const int height = 40;

ContactItemView::ContactItemView(QWidget *parent) : QTreeWidget(parent), my_p_org_id(0)
{
    setRootIsDecorated(false);
    setExpandsOnDoubleClick(false);
    setIndentation(0);
}

QString ContactItemView::getName(const QVariantHash &contact, bool notEmpty)
{
    QString name = getParam(contact, cmd_param_name).toString();
    if(name.simplified().isEmpty())
        name = getParam(contact, cmd_param_terminal_id).toString();
    if(name.simplified().isEmpty())
    {
        if(notEmpty)
            name = getParam(contact, cmd_param_uid).toString();
        else
            name.clear();
    }
    return name;
}

const ContactUser *ContactItemView::findUser(qint64 uid) const
{
    auto it = map_contact.constFind(uid);
    if(it == map_contact.constEnd())
        return Q_NULLPTR;
    return it.operator->();
}

void ContactItemView::handle_contact_list(const QList<QVariantHash> *objs)
{
    /*暂时不存数据库
    LiteDb* db = LiteDb::instance();
    auto db_contact = db->query_contact();
    if(objs)
        //json
        handle_contact_list(*objs, &db_contact, db);
    else
        //db
        handle_contact_list(db_contact.values(), Q_NULLPTR, db);
    */
    if(objs)
        handle_contact_list(*objs, Q_NULLPTR, Q_NULLPTR);
}

ContactUser *ContactItemView::handle_my_contact(QVariantHash &contact)
{
    auto result = handle_contact(contact, map_contact, Q_NULLPTR, Q_NULLPTR, Q_NULLPTR);
    if(auto p_org_id = getParam(contact, 174).toInt())//public static final int cmd_param_p_org_id = 174;
        my_p_org_id = p_org_id;
    return result;
}

static inline bool compareContactUser(const ContactUser *left, const ContactUser *right)
{
    if(left->pinyin.size() > 0 && left->pinyin.at(0).isLetter())
    {
        if((right->pinyin.isEmpty() || !right->pinyin.at(0).isLetter()))
            return true;
    }
    else if(right->pinyin.size() > 0 && right->pinyin.at(0).isLetter())
        return false;
    return left->pinyin.compare(right->pinyin, Qt::CaseInsensitive) < 0;
}

static inline bool isContactHidden(const QString &keyword, const QString &name, const QString &id, const QString &tooltip)
{
    if(keyword.isEmpty() || name.contains(keyword, Qt::CaseInsensitive) || id.contains(keyword))
        return false;
    auto lines = tooltip.split('\n');
    foreach (auto const &line, lines) {
        int start = line.indexOf(": ");
        if(start >= 0 && line.indexOf(keyword, start, Qt::CaseInsensitive))
            return true;
    }
    return false;
}

void ContactItemView::refreshView()
{
    clear();
    if(int map_size = map_contact.size())
    {
        QVector<const ContactUser*> users;
        users.reserve(map_size);
        for(auto it = map_contact.constBegin(); it != map_contact.constEnd(); it++)
        {
            users.append(it.operator ->());
        }
        std::sort(users.begin(), users.end(), compareContactUser);
        QTreeWidgetItem* section = Q_NULLPTR;
        auto myid = ClientCallback::instance()->get_my_id();
        for(int i = 0; i < map_size; i++)
        {
            const ContactUser* user = users[i];
            if(!user || (my_p_org_id > 0 && user->p_org_id != my_p_org_id))
                continue;
            QString first = user->pinyin.left(1);
            if(first.size() > 0 && first[0].isLetter())
                first = first.toUpper();
            else
                first = '#';
            if(!section || section->text(0) != first)
            {
                section = new QTreeWidgetItem(this);
                section->setText(0, first);
                section->setExpanded(true);
                section->setData(0, Qt::BackgroundRole, QColor("#ebecee"));
                section->setFlags(section->flags() & ~Qt::ItemIsSelectable & ~Qt::ItemIsDragEnabled);
                section->setHidden(true);   //为防止child全部是隐藏，因此默认为隐藏
            }
            QTreeWidgetItem* item = new QTreeWidgetItem(section);
            item->setText(0, user->display());
            item->setData(0, Qt::UserRole, user->uid);
            item->setData(0, Qt::DecorationRole, user->decoration(::width, ::height, font()));
            item->setToolTip(0, user->getToolTip());
            if(user->uid == myid)   //自己不能拖
                item->setFlags(item->flags() & ~Qt::ItemIsSelectable & ~Qt::ItemIsDragEnabled);
            else
                item->setFlags(item->flags() & ~Qt::ItemIsSelectable | Qt::ItemIsDragEnabled);
            if(isContactHidden(searchword, item->text(0), item->data(0, Qt::UserRole).toString(), item->toolTip(0)))
                item->setHidden(true);
            else if(section->isHidden())
                section->setHidden(false);
        }
    }
}

void ContactItemView::handle_msg_list(const QList<QVariantHash> &msg_list)
{
    //
}

void ContactItemView::handle_search(const QString &keyword)
{
    if(keyword.compare(searchword, Qt::CaseInsensitive) == 0)
        return;
    searchword = keyword;
    int sectionCount = this->topLevelItemCount();
    for (int iSection = 0; iSection < sectionCount; iSection++) {
        if(auto section = topLevelItem(iSection))
        {
            int count = section->childCount();
            int showCount = 0;
            for(int i = 0; i < count; i++) {
                auto item = section->child(i);
                item->setHidden(isContactHidden(keyword, item->text(0), item->data(0, Qt::UserRole).toString(), item->toolTip(0)));
                showCount += !item->isHidden();
            }
            section->setHidden(showCount == 0);
        }
    }
}

QModelIndexList ContactItemView::selectedIndexes() const
{
    auto current = currentIndex();
    if(current.isValid())
        return QModelIndexList({current});
    return QModelIndexList();
}

static inline void update_contact(qint64 uid, const QVariantHash &hash, LiteDb *db)
{
    QVariantList vars;
    vars << uid;
    QByteArray buffer;
    {
        QDataStream ds(&buffer, QIODevice::WriteOnly);
        ds << hash;
    }
    if(!buffer.isEmpty())
    {
        vars << buffer;
        db->update_contact(vars);
    }
}

ContactUser *ContactItemView::handle_contact(QVariantHash &contactObj, QMap<qint64, ContactUser> &contacts, QList<qint64> *delContactList, QMap<qint64, QVariant> *db_contact, LiteDb *db)
{
    //cmd_param_sex/cmd_param_state/cmd_param_type/cmd_param_ver/cmd_param_face/cmd_param_phone
    //cmd_param_org_id/cmd_param_enabled/cmd_param_imei/cmd_param_party_id/cmd_param_terminal_id/cmd_param_short_number/cmd_param_number
    //cmd_param_visible/cmd_param_iccid/cmd_param_position
    qint64 uid = getParam(contactObj, cmd_param_uid).toLongLong();
    if (uid <= 0)
        return Q_NULLPTR;
    if(getParam(contactObj, cmd_param_type).toInt() == 1)   //type=1是罪犯
        return Q_NULLPTR;
    ContactUser& contact = contacts[uid];
    contact.uid = uid;
    contact.name = getName(contactObj, false);
    contact.phone = getParam(contactObj, cmd_param_phone).toString();
    contact.account = getParam(contactObj, cmd_param_terminal_id).toString();
    contact.p_org_id = getParam(contactObj, 174).toLongLong();

    auto findState = contactObj.find(QString::number(cmd_param_state));
    if(findState != contactObj.end())
    {
        //TODO:获取在线状态
        contactObj.erase(findState);//不保存在线状态
    }
    if(db_contact && db)
    {
        auto findDb = db_contact->find(uid);
        if(findDb != db_contact->end())
        {
            if(findDb->toHash() != contactObj)
                update_contact(uid, contactObj, db);
            db_contact->erase(findDb);
        }
        else
            update_contact(uid, contactObj, db);
    }

    if(delContactList)
        delContactList->removeOne(uid);

    //如果名称相同，则拼音可以不用转
    auto find = map_contact.constFind(contact.uid);
    if(find != map_contact.constEnd() && find->name == contact.name)
        contact.pinyin = contact.pinyin;

    if(contact.pinyin.isEmpty())
    {
        QString display = contact.display();
        for(int i = 0; i < display.size(); i++)
        {
            QCharRef c = display[i];
            std::vector<std::string> py = Hanz2Piny::toPinyinFromUnicode(c.unicode(), false);
            if(py.empty())
                contact.pinyin.append(c);
            else
                contact.pinyin.append(QString::fromLatin1(py[0].c_str()));
        }
    }
    return &contact;
}

void ContactItemView::handle_contact_list(const QList<QVariantHash> &objs, QMap<qint64, QVariant> *db_contact, LiteDb *db)
{
    QList<qint64> delContactList = map_contact.keys();

    const QStringList fields = db_contact ? LiteDb::contact_fields() : QStringList();
    const QMap<QString, QString> fieldMap = {};

    bool transactionStarted = db_contact && (!db_contact->isEmpty() || !objs.isEmpty()) && db && db->beginTransaction();

    QMap<qint64, ContactUser> contacts;
    for(auto contactObj : objs)
    {
        handle_contact(contactObj, contacts, &delContactList, db_contact, db);
    }

    if(db_contact && db)
    {
        for(auto it = db_contact->begin();it!=db_contact->end();it++)
            db->delete_contact(it.key());
    }

    if(transactionStarted && !db->commit())
    {
        db->rollback();
    }

    if(contacts.keys() != map_contact.keys() || contacts != map_contact)
    {
        //TODO:重新排列/刷新应该分别处理
        map_contact.swap(contacts);
        refreshView();
    }
}
